import { defineStore } from "pinia";
import { ref, reactive, watch, computed } from "vue";
import { request } from "@/components/apis";
import { useDebounceFn } from "@vueuse/core";

import { Todo } from "@/components/types";
import { useUserStore } from "./user";

interface StatInfo {
  count: number;
  finished: {
    Normal?: number;
    Important?: number;
    Crucial?: number;
  };
  notFinish: {
    Normal?: number;
    Important?: number;
    Crucial?: number;
  };
}

export const useTodosStore = defineStore("todos", () => {
  const userStore = useUserStore();
  const todos = ref<Todo[]>([]),
    loading = ref(false),
    ending = ref(false),
    page = ref(0),
    count = ref(0),
    limit = ref(3),
    selected = ref<Todo>(),
    query = reactive({
      days: "all",
      priority: "all",
      finished: "all",
    }),
    stat = reactive<StatInfo>({
      count: 0,
      finished: {},
      notFinish: {},
    }),
    // methods
    search = async () => {
      loading.value = true;
      const { data } = await request<Todo>("/todos", {
        params: {
          ...query,
          limit: limit.value,
          offset: (page.value - 1) * limit.value,
        },
      });
      if (data.success) {
        count.value = data.query?.count || 0;
        if (data.query?.results) {
          if (page.value == 1) todos.value = data.query?.results;
          else todos.value.push(...data.query?.results);
        }
      }
      loading.value = false;
    },
    addTodo = async (values: Partial<Todo>) => {
      const { data } = await request<Todo>("/todo", {
        method: "POST",
        data: values,
      });
      const { success, object } = data;
      if (success && object) {
        todos.value.unshift(object);
        performance();
      }
      return data;
    },
    editTodo = async (values: Partial<Todo>) => {
      if (!selected.value) return;
      const { data } = await request<Todo>(`/todo/${selected.value.id}`, {
        method: "PUT",
        data: values,
      });
      const { success, object } = data;
      if (success && object) {
        todos.value = todos.value.map((i) => (i.id == object?.id ? object : i));
        performance();
      }
      return data;
    },
    removeTodo = async () => {
      if (!selected.value) return;
      const { data } = await request<Todo>(`/todo/${selected.value.id}`, {
        method: "DELETE",
      });
      const { success, object } = data;
      if (success && object) {
        todos.value = todos.value.filter((i) => i.id != object.id);
        performance();
      }
      return data;
    },
    finishTodo = async () => {
      if (!selected.value) return;
      const { data } = await request<Todo>(
        `/todo/finish/${selected.value.id}`,
        {
          method: "PUT",
        }
      );
      const { success, object } = data;
      if (success && object) {
        todos.value = todos.value.map((i) => (i.id == object.id ? object : i));
        performance();
      }
      return data;
    },
    load = useDebounceFn(async () => {
      if (ending.value) return;
      page.value += 1;
      await performance();
      await search();
      ending.value = page.value >= Math.ceil(count.value / limit.value);
    }, 200),
    performance = async () => {
      const { data } = await request("/stat");
      if (data.success) {
        Object.assign(stat, data.stat);
      }
    },
    reset = () => {
      ending.value = false;
      page.value = 0;
      count.value = 0;
      // todos.value = [];
      if (userStore.isAuth) load();
      else todos.value = [];
    };
  // watch condition
  watch(query, () => reset(), { deep: true });
  // computed
  const finishCount = computed(() =>
      Object.values(stat.finished).reduce((p, i) => p + i, 0)
    ),
    notFinishCount = computed(() =>
      Object.values(stat.notFinish).reduce((p, i) => p + i, 0)
    ),
    index = computed(() =>
      todos.value.findIndex((i) => i.id == selected.value?.id)
    );

  return {
    todos,
    loading,
    ending,
    page,
    count,
    limit,
    query,
    stat,
    finishCount,
    notFinishCount,
    selected,
    index,
    load,
    reset,
    search,
    addTodo,
    editTodo,
    removeTodo,
    finishTodo,
  };
});
